﻿using MLSharp.Classification;
using SVM;

namespace MLSharp.SupportVectorMachines
{
	/// <summary>
	/// Support vector machine classifier trained by <see cref="LibSvmClassifierFactory"/>.
	/// </summary>
	public class LibSvmClassifier : IClassifier
	{
		#region Public Properties

		/// <summary>
		/// The underlying SVM Model.
		/// </summary>
		public Model Model { get; private set; }

		#endregion

		#region Public Constructors

		/// <summary>
		/// Creates a new vector that represents the specified model.
		/// </summary>
		/// <param name="model"></param>
		public LibSvmClassifier(Model model)
		{
			Model = model;
		}

		#endregion

		#region Implementation of IClassifier

		/// <summary>
		/// Classifies all the instances in the specified data set.
		/// </summary>
		/// <param name="dataSet">The data set to classify.</param>
		/// <returns>The results of classifying each instance.</returns>
		public ClassificationResult[] Classify(IDataSet dataSet)
		{
			Node[][] instances = dataSet.GetInstancesAsNodes();

			ClassificationResult[] results = new ClassificationResult[dataSet.Instances.Count];

			string[] classValues = dataSet.Attributes[dataSet.TargetAttributeIndex].PossibleValues;

			for (int i=0; i < results.Length; i++)
			{				
				double[] probabilities = Prediction.PredictProbability(Model, instances[i]);

				string predictedClass;
				double confidence;

				//Assign the class and confidence based on which probability is larger.
				//If the model learned to predict a single class, there will only be one probability. 
				if (probabilities.Length == 1 || probabilities[0] > probabilities[1])
				{
					//The Model.ClassLabels value is theindex of the class value.
					predictedClass = classValues[Model.ClassLabels[0]];
					confidence = probabilities[0];
				}
				else
				{
					predictedClass = classValues[Model.ClassLabels[1]];
					confidence = probabilities[1];
				}

				ClassificationResult result = new ClassificationResult(predictedClass, dataSet.Instances[i].ClassValue)
				                              	{
				                              		ID = dataSet.Instances[i].Label,
				                              		Confidence = confidence
				                              	};

				results[i] = result;
			}

			return results;
		}

		#endregion
	}
}
